﻿using System;
using System.Text;
using System.Web.Mvc;
using System.Linq;
using Quizz.Infrastructure;
using Quizz.Library.Common;
using Quizz.Library.Helper;
using Quizz.Library.QuizzServiceReference;
using System.Collections.Generic;
using Quizz.Infrastructure.Models;
using Quizz.Infrastructure.Common;
using Quizz.Infrastructure.Util;

namespace Quizz.Library.Actions
{
    public class UserAction : BasicAction
    {
        #region Fields

        private const string LockUserCount = "LockUserCount{0}";
        private const string LockUserTime = "LockUserTime{0}";

        #endregion

        public UserAction(System.Web.Mvc.Controller controller) : base(controller)
        {
        }

        public JsonResult CheckLogin(string username, string password)
        {
            using(var proxy = new QuizzProjectServiceClient())
            {
                var clientIp = Request.UserHostAddress;
                var keyLockUserCount = string.Format(LockUserCount, clientIp);
                var keyLockUserTime = string.Format(LockUserTime, clientIp);

                // Check if user IP is locked
                if (AccessFactory.Cache[keyLockUserTime] != null)
                {
                    var diff = (DateTime.Now - (DateTime)AccessFactory.Cache[keyLockUserTime]).TotalSeconds;
                    if (diff > (AccessFactory.LoginFailLockTimeout * 60))
                    {
                        AccessFactory.Cache.Remove(keyLockUserCount);
                        AccessFactory.Cache.Remove(keyLockUserTime);
                    }
                    else
                    {
                        return CommonMethods.CreateJson(
                                new
                                    {
                                        result = false,
                                        message = string.Format("Tài khoản của bạn tạm thời bị khóa. Vui lòng đăng nhập lại sau {0} phút", (int) (AccessFactory.LoginFailLockTimeout - (diff/60)))
                                    }, false);
                    }
                }

                // User IP is not locked
                var user = proxy.UserGetByEmail(username);
                if (user == null || !user.Password.Equals(password, StringComparison.OrdinalIgnoreCase) || user.Status == (int)UserStatus.Deleted)
                {
                    if (AccessFactory.Cache[keyLockUserCount] == null)
                    {
                        AccessFactory.Cache[keyLockUserCount] = 1;
                    }
                    else
                    {
                        var count = (int)AccessFactory.Cache[keyLockUserCount] + 1;
                        AccessFactory.Cache.Remove(keyLockUserCount);
                        AccessFactory.Cache.Insert(keyLockUserCount, count);

                        if (count >= AccessFactory.MaxLoginFailCount)
                        {
                            AccessFactory.Cache.Insert(keyLockUserTime, DateTime.Now);
                            var diff = (DateTime.Now - (DateTime)AccessFactory.Cache[keyLockUserTime]).Seconds;
                            return CommonMethods.CreateJson(
                                    new
                                        {
                                            result = false,
                                            message = string.Format("Tài khoản của bạn tạm thời bị khóa. Vui lòng đăng nhập lại sau {0} phút", (int) (AccessFactory.LoginFailLockTimeout - (diff/60)))
                                        }, false);
                        }
                    }

                    var errorCount = (int) AccessFactory.Cache[keyLockUserCount];
                    var errorMessage = "Tên đăng nhập hoặc mật khẩu không đúng !";
                    if (errorCount >= 2)
                    {
                        errorMessage += string.Format(" Tài khoản của bạn sẽ bị khóa sau {0} lần thất bại nữa.",
                                                      AccessFactory.MaxLoginFailCount - errorCount);
                    }

                    return CommonMethods.CreateJson(new {result = false, message = errorMessage}, false);
                }

                if (user.Status == (int)UserStatus.Locked && user.Password.Equals(password, StringComparison.OrdinalIgnoreCase))
                {
                    return CommonMethods.CreateJson(new { result = false, message = "Tài khoản của bạn tạm thời bị khóa bởi người quản trị." }, false);
                }

                // Every thing is ok
                // 1. Remove cache
                // 2. Log to session
                AccessFactory.Cache.Remove(keyLockUserCount);
                AccessFactory.Cache.Remove(keyLockUserTime);
                AccessFactory.Login(user);

                return CommonMethods.CreateJson(new {result = true}, false);
            }
        }

        public bool IsLoggedIn()
        {
            return AccessFactory.IsUserLogined();
        }

        public JsonResult GetUserPage(int page, int count, string orderColum)
        {
            Session[Constants.UserListCurrent] = page;
            Session[Constants.UserListOrder] = orderColum;
            using (var proxy = new QuizzProjectServiceClient())
            {
                var data = proxy.UserGetPage(page, count, orderColum);
                var pageCount = (int)Math.Ceiling((double)data.ResultCount/count);

                return CommonMethods.CreateJson(new
                                                    {
                                                        result = true,
                                                        count = data.ResultCount,
                                                        data = BuildUserList(data.Users),
                                                        paging = BuildPagination(pageCount, page)
                                                    }, false);
            }
        }

        public JsonResult AddUser(User user)
        {
            // Need validate first
            var validateResult = ValidateAddUser(user);
            if (validateResult.HasError())
            {
                return CommonMethods.CreateJson(new { result = false, message = validateResult.ToString("<br />") }, false);
            }

            // Default data
            user.RegisterDate = DateTime.Now;

            using (var proxy = new QuizzProjectServiceClient())
            {
                proxy.UserInsert(user);
            }

            return CommonMethods.CreateJson(new { result = false }, false);
        }

        public JsonResult LoadUser(long id)
        {
            using (var proxy = new QuizzProjectServiceClient())
            {
                var user = proxy.UserGetById(id);
                if (user == null)
                {
                    return CommonMethods.CreateJson(new { result = false }, false);
                }
                return CommonMethods.CreateJson(new { result = true, User = user }, false);
            }
        }

        public JsonResult DeleteUser(long id)
        {
            if (id == AccessFactory.CurrentUser.Id || id == Constants.ROOT_ADMIN_ID)
            {
                return CommonMethods.CreateJson(new { result = false }, false);
            }
            using (var proxy = new QuizzProjectServiceClient())
            {
                try
                {
                    proxy.UserDelete(id);
                    return CommonMethods.CreateJson(new { result = true }, false);
                }
                catch { return CommonMethods.CreateJson(new { result = false }, false); }
            }
        }

        private void UserDelete(long id)
        {
            throw new NotImplementedException();
        }

        public JsonResult EditUser(User user)
        {
            using (var proxy = new QuizzProjectServiceClient())
            {
                var oldUser = proxy.UserGetById(user.Id);
                if (oldUser == null)
                {
                    return CommonMethods.CreateJson(new { result = false }, false);
                }

                // Xu ly tiep
                if (user.Id != AccessFactory.CurrentUser.Id || user.Id == Constants.ROOT_ADMIN_ID)
                {
                    oldUser.RoleId = user.RoleId;
                    oldUser.Status = user.Status;
                }

                oldUser.FirstName = user.FirstName;
                oldUser.LastName = user.LastName;
                oldUser.Phone = user.Phone;
                oldUser.Address = user.Address;
                if (user.Password != "Tt!@#123")
                {
                    oldUser.Password = user.Password;
                }

                try
                {
                    proxy.UserUpdate(oldUser);
                    return CommonMethods.CreateJson(new { result = true }, false);
                }
                catch (Exception ex)
                {
                    return CommonMethods.CreateJson(new { result = false, message = ex.ToString() }, false);
                }
            }
        }

        #region Private methods

        private string BuildUserList(IList<User> users)
        {
            var builder = new StringBuilder();
            IDictionary<long, string> roles;
            using (var proxy = new QuizzProjectServiceClient())
            {
                var items = proxy.RoleGetAll();
                roles = items.ToDictionary(k => k.Id, v => v.Name);
            }
            var count = 1;
            foreach (var user in users)
            {
                builder.Append("<tr>");
                builder.AppendFormat("<td>{0}</td>", count);
                builder.AppendFormat("<td>{0}</td>", user.Email);
                builder.AppendFormat("<td>{0}</td>", user.FirstName);
                builder.AppendFormat("<td>{0}</td>", user.LastName);
                builder.AppendFormat("<td>{0}</td>", user.Phone);
                builder.AppendFormat("<td>{0}</td>", user.RegisterDate.ToString("dd/MM/yyyy HH:mm:ss"));
                builder.AppendFormat("<td>{0}</td>", Utilities.UserStatusToString((UserStatus)user.Status));
                builder.AppendFormat("<td>{0}</td>", roles[user.RoleId]);
                builder.AppendFormat(@"<td>
                        <a class='inline-button' onclick='LoadEditUser({0});' href='javascript:void(0)'><img alt='Sửa' src='/images/edit.png' /></a>
                        <a class='inline-button' onclick='ShowConfirmDelete({0});' href='javascript:void(0)'><img alt='Xóa' src='/images/delete2.png' /></a>
                    </td>", user.Id);
                builder.Append("</tr>");
                count++;
            }

            return builder.ToString();
        }

        private string BuildPagination(int page, int current)
        {
            var result = new StringBuilder();

            if (current == 0)
            {
                result.Append("<span class=\"disable\">&lt;&lt;</span>");
            }
            else
            {
                result.Append("<a class=\"prev\" href=\"javascript:void(0)\" onclick=\"GetUserPage(_currentPage-1, _itemPerPage, _currentOrder);\">&lt;&lt;</a>");
            }

            var from = Math.Max(0, current - 5);
            var to = Math.Min(page - 1, current + 5);

            if (from != 0)
            {
                result.Append("<span class=\"pos\">...</span>");
            }

            for (var i = from; i <= to; i++)
            {
                if (current == i)
                {
                    result.AppendFormat("<span class=\"current\">{0}</span>", i + 1);
                }
                else
                {
                    result.AppendFormat("<a href=\"javascript:void(0)\" onclick=\"GetUserPage({0}, _itemPerPage, _currentOrder);\">{1}</a>", i, i + 1);
                }
            }

            if (to < page-1)
            {
                result.Append("<span class=\"pos\">...</span>");
            }

            if (current == page - 1)
            {
                result.Append("<span class=\"disable\">&gt;&gt;</span>");
            }
            else
            {
                result.Append("<a class=\"prev\" href=\"javascript:void(0)\" onclick=\"GetUserPage(_currentPage+1, _itemPerPage, _currentOrder);\">&gt;&gt;</a>");
            }

            return result.ToString();
        }

        private ErrorReportResult ValidateAddUser(User user)
        {
            var result = new ErrorReportResult();

            if (!CommonValidate.IsEmail(user.Email))
                result.AddError("Địa chỉ email không hợp lệ.");
            using (var proxy = new QuizzProjectServiceClient())
            {
                if (!proxy.UserIsEmailAvailable(user.Email))
                    result.AddError("Địa chỉ email đã được sử dụng, vui lòng chọn email khác.");
            }

            return result;
        }

        #endregion
    }
}
